python opencv measure distance two shapes

35

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

// since its just two elements, then a tuple return should suffice.
tuple<size_t, size_t> getTheTwoLargestContours(const vector<vector<Point>>& contours)
{
    size_t largestLoc = 0, secondLargestLoc = 0;
    double largestArea = 0, secondLargestArea = 0;

    for(size_t index = 0; index < contours.size(); ++index)
    {
        double area = contourArea(contours[index]);

        // first check to see if this area is the largest
        if(area > largestArea)
        {
            largestArea = area;
            largestLoc = index;
        }
        else if(area > secondLargestArea) // if not then its probably the second largest, maybe?
        {
            secondLargestArea = area;
            secondLargestLoc = index;
        }
    }

    return make_tuple(largestLoc, secondLargestLoc);
}

int main(void)
{
    // OpenCV is shying away from using the CV prefix
    Mat frame = imread("cards.png", IMREAD_GRAYSCALE);

    threshold(frame, frame, 127, 255, THRESH_BINARY);

    imshow("f", frame);

    Mat flt_frame(frame.rows, frame.cols, CV_32F);

    for (int j = 0; j < frame.rows; j++)
        for (int i = 0; i < frame.cols; i++)
            flt_frame.at<float>(j, i) = frame.at<unsigned char>(j, i) / 255.0f;

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours(frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    if(contours.size() < 2)
    {
        cout << "Error: must have 2 or more contours." << endl;
        return 0;
    }

    tuple<size_t, size_t> locations = getTheTwoLargestContours(contours);

    /*
     std::get<index>(tuple) is how you access tuple elements.
     Read more here: http://www.geeksforgeeks.org/tuples-in-c/

     Index 0 of locations is where the largest contour is located.
     So I calculate its moment along with its center.
     This logic can be converted into a loop should more contours be needed.
     */
    Moments mu = moments(contours[get<0>(locations)], false);
    Point2d largestMassCenter = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);

    // do the same thing for the second largest
    mu = moments(contours[get<1>(locations)], false);
    Point2d secondLargestMassCenter = Point2d(mu.m10 / mu.m00, mu.m01 / mu.m00);

    // OpenCV has a norm function for calculating the Euclidean distance
    double distance = norm(largestMassCenter - secondLargestMassCenter);

    cout << "Distance (in pixels): " << distance << endl;

    Mat output ...

Comments

Submit
0 Comments